#include "stdafx.h"
#include "gp_Ax2.h"
#include "gp_Pnt.h"
#include "gp_Dir.h"
#include "gp_Ax1.h"
#include "gp_Trsf.h"
#include "gp_Vec.h"
#include "gp_Ax3.h"
#include "gp.h"
#include "gp_Ax1.h"


gp_Ax3::gp_Ax3 (const gp_Pnt& P,
	const gp_Dir& V) : axis(P,V)
{
	double A = V.X();
	double B = V.Y();
	double C = V.Z();
	double Aabs = A;
	if (Aabs < 0) Aabs = - Aabs;
	double Babs = B;
	if (Babs < 0) Babs = - Babs;
	double Cabs = C;
	if (Cabs < 0) Cabs = - Cabs;
	gp_Dir D;

	//  pour determiner l axe X :
	//  on dit que le produit scalaire Vx.V = 0. 
	//  et on recherche le max(A,B,C) pour faire la division.
	//  l une des coordonnees du vecteur est nulle. 

	if     ( Babs <= Aabs && Babs <= Cabs) {
		if (Aabs > Cabs) D.SetCoord(-C,0., A);
		else             D.SetCoord( C,0.,-A);
	}
	else if( Aabs <= Babs && Aabs <= Cabs) {
		if (Babs > Cabs) D.SetCoord(0.,-C, B);
		else             D.SetCoord(0., C,-B);
	}
	else {
		if (Aabs > Babs) D.SetCoord(-B, A,0.);
		else             D.SetCoord( B,-A,0.);
	}
	vxdir = D;
	vydir = V.Crossed(vxdir);
}

void  gp_Ax3::Mirror(const gp_Pnt& P)
{
	axis.Mirror (P);
	vxdir.Reverse ();
	vydir.Reverse ();
}

gp_Ax3  gp_Ax3::Mirrored(const gp_Pnt& P)const
{
	gp_Ax3 Temp = *this;
	Temp.Mirror (P);
	return Temp;
}

void  gp_Ax3::Mirror(const gp_Ax1& A1)
{
	vydir.Mirror (A1);
	vxdir.Mirror (A1);
	axis.Mirror (A1);
}

gp_Ax3  gp_Ax3::Mirrored(const gp_Ax1& A1)const
{
	gp_Ax3 Temp = *this;
	Temp.Mirror (A1);
	return Temp;
}

void  gp_Ax3::Mirror(const gp_Ax2& A2)
{
	vydir.Mirror (A2);
	vxdir.Mirror (A2);
	axis.Mirror (A2);
}

gp_Ax3  gp_Ax3::Mirrored(const gp_Ax2& A2)const
{
	gp_Ax3 Temp = *this;
	Temp.Mirror (A2);
	return Temp;
}


 gp_Ax3::gp_Ax3() : vydir(0.,1.,0.), vxdir(1.,0.,0.)
{ }

 gp_Ax3::gp_Ax3(const gp_Ax2& A) :
axis(A.Axis()),
vydir(A.YDirection()),
vxdir(A.XDirection())
{ }

 gp_Ax3::gp_Ax3(const gp_Pnt& P, const gp_Dir& N, const gp_Dir& Vx) :
axis(P, N), vydir(N), vxdir(N)
{
  vxdir.CrossCross(Vx, N);
  vydir.Cross(vxdir);
}

 void  gp_Ax3::XReverse()
{ vxdir.Reverse(); }

 void  gp_Ax3::YReverse()
{ vydir.Reverse(); }

 void  gp_Ax3::ZReverse()
{ axis.Reverse();  }

 void  gp_Ax3::SetAxis(const gp_Ax1& A1)
{
  bool direct = Direct();
  axis = A1;
  vxdir = axis.Direction().CrossCrossed (vxdir, axis.Direction());
  if(direct) { vydir = axis.Direction().Crossed(vxdir); }
  else       { vydir = vxdir.Crossed(axis.Direction()); }
}

 void  gp_Ax3::SetDirection(const gp_Dir& V)
{
  bool direct = Direct();
  axis.SetDirection (V);
  vxdir = V.CrossCrossed (vxdir, V);
  if (direct) { vydir = V.Crossed (vxdir); }
  else        { vydir = vxdir.Crossed (V); }
}

 void  gp_Ax3::SetLocation(const gp_Pnt& P)
{  axis.SetLocation(P); }

 void  gp_Ax3::SetXDirection(const gp_Dir& Vx)
{
  bool direct = Direct();
  vxdir = axis.Direction().CrossCrossed (Vx, axis.Direction());
  if (direct) { vydir = axis.Direction().Crossed(vxdir); }
  else        { vydir = vxdir.Crossed(axis.Direction()); }
}

 void  gp_Ax3::SetYDirection(const gp_Dir& Vy)
{
  bool direct = Direct();
  vxdir = Vy.Crossed (axis.Direction());
  vydir = (axis.Direction()).Crossed (vxdir);
  if (!direct) { vxdir.Reverse(); }
}

 double  gp_Ax3::Angle(const gp_Ax3& Other) const 
{ return axis.Angle (Other.axis); }

 const gp_Ax1&  gp_Ax3::Axis()const
{  return axis; }

 gp_Ax2  gp_Ax3::Ax2()const 
{
  gp_Dir zz = axis.Direction();
  if (!Direct()) { zz.Reverse(); }
  return gp_Ax2 (axis.Location(),zz,vxdir);
}

 const gp_Dir&  gp_Ax3::Direction()const
{   return axis.Direction(); }

 const gp_Pnt&  gp_Ax3::Location()const
{   return axis.Location(); }

 const gp_Dir&  gp_Ax3::XDirection()const
{  return vxdir;  }

 const gp_Dir&  gp_Ax3::YDirection()const
{  return vydir; }

 bool  gp_Ax3::Direct()const 
{ return (vxdir.Crossed(vydir).Dot(axis.Direction()) > 0.); }

 bool gp_Ax3::IsCoplanar
(const gp_Ax3& Other, 
 const double LinearTolerance, 
 const double AngularTolerance)const 
{
  gp_Vec vec(axis.Location(),Other.axis.Location());
  double D1 = gp_Vec(axis.Direction()      ).Dot(vec);
  if (D1 < 0) D1 = - D1;
  double D2 = gp_Vec(Other.axis.Direction()).Dot(vec);
  if (D2 < 0) D2 = - D2;
  return (D1 <= LinearTolerance && D2 <= LinearTolerance &&
          axis.IsParallel (Other.axis, AngularTolerance));
}

 bool gp_Ax3::IsCoplanar
(const gp_Ax1& A1, 
 const double LinearTolerance, 
 const double AngularTolerance)const 
{
  gp_Vec vec(axis.Location(),A1.Location());
  double D1 = gp_Vec(axis.Direction()).Dot(vec);
  if (D1 < 0) D1 = - D1;
  double D2 = (gp_Vec(A1.Direction()).Crossed(vec)).Magnitude();
  if (D2 < 0) D2 = - D2;
  return (D1 <= LinearTolerance && D2 <= LinearTolerance &&
          axis.IsNormal (A1, AngularTolerance));
}

 void  gp_Ax3::Rotate(const gp_Ax1& A1,
			    const double Ang)
{
  axis.Rotate (A1,Ang);
  vxdir.Rotate (A1,Ang);
  vydir.Rotate (A1,Ang);
}

 gp_Ax3  gp_Ax3::Rotated(const gp_Ax1& A1,
			       const double Ang)const
{
  gp_Ax3 Temp = *this;
  Temp.Rotate (A1,Ang);
  return Temp;
}

 void  gp_Ax3::Scale(const gp_Pnt& P, const double S)
{
  axis.Scale (P,S);
  if (S < 0.) {
    vxdir.Reverse ();
    vydir.Reverse ();
  }
}

 gp_Ax3  gp_Ax3::Scaled(const gp_Pnt& P,
			      const double S)const
{
  gp_Ax3 Temp = *this;
  Temp.Scale (P,S);
  return Temp;
}

 void  gp_Ax3::Transform(const gp_Trsf& T)
{
  axis.Transform (T);
  vxdir.Transform (T);
  vydir.Transform (T);
}

 gp_Ax3  gp_Ax3::Transformed(const gp_Trsf& T)const
{
  gp_Ax3 Temp = *this;
  Temp.Transform (T);
  return Temp;
}

 void  gp_Ax3::Translate(const gp_Vec& V)
{ axis.Translate (V); }

 gp_Ax3  gp_Ax3::Translated(const gp_Vec& V)const
{
  gp_Ax3 Temp = *this;
  Temp.Translate (V);
  return Temp;
}

 void  gp_Ax3::Translate(const gp_Pnt& P1, const gp_Pnt& P2)
{ Translate(gp_Vec(P1,P2)); }

 gp_Ax3  gp_Ax3::Translated(const gp_Pnt& P1, const gp_Pnt& P2)const
{ return Translated(gp_Vec(P1,P2)); }
